
package com.treasure.service.commons.lang.util;

import org.slf4j.helpers.MessageFormatter;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;

/**
 * 字符串工具类
 * @author <a href="mailto:19919866605@163.com">Pan Xinwen</a>
 * @version 1.0 2018年5月29日 上午11:04:01
 */
public abstract class StringUtil {
	/** 随机数对象 */
	private static final Random random = new Random();
	/** 数字与字母字典 */
	private static final char[] LETTER_AND_DIGIT = ("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray();
	/** 数字与字母字典长度 */
	private static final int LETTER_AND_DIGIT_LENGTH = LETTER_AND_DIGIT.length;
	/** 使用Log4j2的消息格式化工厂 */


	/**
	 * 检测字符串是否为空字符串
	 * 字符串为空的标准：null或全部由空字符组成的字符串
	 * @param str 待检测字符串
	 * @return
	 * <li>true：字符串是空字符串</li>
	 * <li>false：字符串不是空字符串</li>
	 */
	public static boolean isEmpty(String str) {
		return (str == null|| str.equals("null")|| str.trim().length() == 0);
	}


	/**
	 * 检测字符串是否为空字符串
	 * 字符串为空的标准：null或全部由空字符组成的字符串
	 * @param obj 待检测字符串
	 * @return
	 * <li>true：字符串是空字符串</li>
	 * <li>false：字符串不是空字符串</li>
	 */
	public static boolean isEmpty(Object obj) {

		return (obj == null || obj.toString().trim().length() == 0);

	}

	/**
	 * 检测字符串是否不为空字符串
	 * 字符串为空的标准：null或全部由空字符组成的字符串
	 * @param str 待检测字符串
	 * @return
	 * <li>true：字符串不是空字符串</li>
	 * <li>false：字符串是空字符串</li>
	 * @see #isEmpty(String)
	 */
	public static boolean isNotEmpty(Object str) {
		return !isEmpty(str);
	}



	/**
	 * 转换字符串
	 * @param input 待转换字符串
	 * @param defVal 默认转换值
	 * @return 转换后的字符串
	 * <li>字符串为null或全部由空白字符组成的字符串时，返回defVal参数指定的值</li>
	 * <li>其他情况，返回去掉字符串两端空白字符后的字符串</li>
	 */
	public static String getString(String input, String defVal) {
		return (isEmpty(input)) ? defVal : input.trim();
	}

	/**
	 * 生成固定长度的随机字符串
	 * @param len 随机字符串长度
	 * @return 生成的随机字符串
	 */
	public static String getRandomString(final int len) {
		if (len < 1) return "";
		StringBuilder sb = new StringBuilder(len);
		for (int i = 0; i < len; i++) {
			sb.append(LETTER_AND_DIGIT[random.nextInt(LETTER_AND_DIGIT_LENGTH)]);
		}
		return sb.toString();
	}

	/**
	 * 生成固定长度的随机字符串
	 * @param len 随机字符串长度
	 * @param dictionary 字符串字典
	 * @return 生成的随机字符串
	 */
	public static String getRandomString(final int len, char[] dictionary) {
		if (len < 1) return "";
		StringBuilder sb = new StringBuilder(len);
		for (int i = 0; i < len; i++) {
			sb.append(dictionary[random.nextInt(dictionary.length)]);
		}
		return sb.toString();
	}

	/**
	 * 创建一个新的字符串
	 * @param bytes 字符串内容字节数组
	 * @param charset 字符串字节编码
	 * @return 新创建的字符串
	 */
	public static String newString(byte[] bytes, String charset) {
		try {
			return new String(bytes, charset);
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException("不支持的字符集：" + charset, e);
		}
	}

	/**
	 * 取得字符串字节数组
	 * @param str 字符串
	 * @param charset 字符串字节编码
	 * @return 字符串内容字节数组
	 */
	public static byte[] getBytes(String str, String charset) {
		if (str == null) return null;
		try {
			return str.getBytes(charset);
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException("不支持的字符集：" + charset, e);
		}
	}

	/**
	 * 从右侧开始截取固定长度的字符串
	 * @param str 待截取字符串
	 * @param length 截取的长度
	 * @return
	 * <li>null：字符串为空或字符串长度小于截取的长度</li>
	 * <li>非null：截取字符串后的结果</li>
	 */
	public static String right(String str, int length) {
		return (str == null || str.length() < length) ? null : str.substring(str.length() - length);
	}
	/**
	 * 从左侧开始截取固定长度的字符串
	 * @param str 待截取字符串
	 * @param length 截取的长度
	 * @return
	 * <li>null：字符串为空或字符串长度小于截取的长度</li>
	 * <li>非null：截取字符串后的结果</li>
	 */
	public static String left(String str, int length) {
		return (str == null || str.length() < length) ? null : str.substring(0, length);
	}

	/**
	 * 截取定长字符串（中文、字符、字母、数字……）
	 * @param str
	 * @param fixedWidth
	 * @return
	 */
	public static String subFixedWidthString(String str, int fixedWidth) {
		if(str.length() <= fixedWidth) {
			return str;
		}else{
			StringBuilder ret = new StringBuilder();
		    fixedWidth = fixedWidth << 1;
		    int currentWidth = 0;
		    for (int i = 0; i < str.length(); i++) {
		        char ch = str.charAt(i);
		        currentWidth += (ch < 128) ? 1 : 2;
		        if (currentWidth > fixedWidth) break;
		        ret.append(ch);
		    }
		    ret.append("…");
		    return ret.toString();
		}
	}

	/**
	 * 比较两个字符串大小
	 * @param str1 字符串1
	 * @param str2 字符串2
	 * @return
	 * <li>-1：str1小</li>
	 * <li>0：两字符串相等</li>
	 * <li>1：str2小</li>
	 */
	public static int compare(String str1, String str2) {
		if (str1 == null && str2 == null) return 0;
		if (str1 == null) return -1;
		if (str2 == null) return 1;

		int len1 = str1.length();
		int len2 = str2.length();
		int len = Math.min(len1, len2);
		for (int i = 0; i < len; i++) {
			char ch1 = str1.charAt(i);
			char ch2 = str2.charAt(i);
			if (ch1 == ch2) continue;
			return (ch1 < ch2) ? -1 : 1;
		}

		if (len1 == len2) return 0;
		return (len1 < len2) ? -1 : 1;
	}

	/**
	 * 根据参数填充占位符,构建字符串消息,例如:
	 * msg=我是{} params:小明 返回值为:我是小明
	 * @param message
	 * @param params
	 * @return
	 */
	public static String buildMessage(String message, Object... params) {
//		return messageFactory.newMessage(msg,params).getFormattedMessage();
        if (params != null) {
            message = MessageFormatter.arrayFormat(message, params).getMessage();
        }
        return message;
	}

	/**
	 * 过滤空格
	 * @param str 待过滤字符串
	 * @return 过滤结果
	 */
	public static String trim (String str) {
		return str == null ? null : str.trim();
	}

	/**
	 * 将字符串指定索引位的字符转换为大写
	 * @param source
	 * @param index
	 *
	 * @return
	 */
	public static String toUpperCase(String source, int index) {
		char[] chars = source.toCharArray();
		chars[index] = Character.toUpperCase(chars[index]);
		return new String(chars);
	}


	// GENERAL_PUNCTUATION 判断中文的“号
	// CJK_SYMBOLS_AND_PUNCTUATION 判断中文的。号
	// HALFWIDTH_AND_FULLWIDTH_FORMS 判断中文的，号
	public static final boolean isChinese(char c) {
		Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
		if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
				|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
				|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
				|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
				|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
				|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
			return true;
		}
		return false;
	}


	public static final boolean isChinese(String strName) {
		char[] ch = strName.toCharArray();
		for (int i = 0; i < ch.length; i++) {
			char c = ch[i];
			if (isChinese(c)) {
				return true;
			}
		}
		return false;
	}

	public static final boolean isMobile(String str) {
        Pattern pattern = Pattern.compile ("^[1](([3,4,5,7,8][0-9]{9})|(99)[0-9]{8})$");// 验证手机号
		Matcher matcher = pattern.matcher(str);
		boolean b = matcher.matches();
		return b;
	}

	public static final boolean isEmail(String str) {
		String paString ="^([a-zA-Z0-9]*[-_]?[a-zA-Z0-9]+)*@([a-zA-Z0-9]*[-_]?[a-zA-Z0-9]+)+[\\.][A-Za-z]{2,3}([\\.][A-Za-z]{2})?$";
		Pattern pattern = Pattern.compile(paString); // 验证邮箱
		Matcher matcher = pattern.matcher(str);
		boolean b = matcher.matches();
		return b;
	}

	public static String hiddenName(String name) {
		if (isEmpty(name)) return "";

		if (name.length() <= 2) return name.charAt(0) + "*";
		else {
			StringBuilder sb = new StringBuilder();
			sb.append(name.charAt(0));
			IntStream.range(0, name.length() - 2).forEach(s -> sb.append("*"));
			sb.append(name.charAt(name.length() - 1));
			return sb.toString();
		}
	}

	public static String hiddenMobile(String mobile) {
		return left(mobile, 3) + "****" + right(mobile, 4);
	}
	public static String hiddenBankId(String bankId){
		if(isEmpty(bankId)){
			return "";
		}
		StringBuilder sb = new StringBuilder();
		sb.append(left(bankId, 4));
		IntStream.range(0, bankId.length() - 8).forEach(s -> sb.append("*"));
		sb.append(right(bankId, 4));
		return sb.toString();
	}
	public static String hiddenIDCardNumber(String idcardNumber) {
		if (isEmpty(idcardNumber)) return "";

		if (idcardNumber.length() <= 15) return left(idcardNumber, 4) + "******" + right(idcardNumber, 5);
		else return left(idcardNumber,2 ) + "****" + idcardNumber.substring(6, 8) + "******" + right(idcardNumber, 4);
	}

    public static boolean isBlank(CharSequence cs) {
        int strLen;
        if(cs != null && (strLen = cs.length()) != 0) {
            for(int i = 0; i < strLen; ++i) {
                if(!Character.isWhitespace(cs.charAt(i))) {
                    return false;
                }
            }

            return true;
        } else {
            return true;
        }
    }

    public static boolean isNotBlank(CharSequence cs) {
        return !isBlank(cs);
    }

    public static boolean extract(Integer probability){
    	int n=(int)(Math.random()*100+1);
    	return (n<probability+1);
    }


    /**
     * 获取编码字符集
     * @param request
     * @param response
     * @return String
     */
    public static String getCharacterEncoding(HttpServletRequest request,
                                              HttpServletResponse response) {

        if(null == request || null == response) {
            return "gbk";
        }

        String enc = request.getCharacterEncoding();
        if(null == enc || "".equals(enc)) {
            enc = response.getCharacterEncoding();
        }

        if(null == enc || "".equals(enc)) {
            enc = "gbk";
        }

        return enc;
    }

    public static boolean isEqual(Object str1 ,Object str2){

        return (isEmpty(str1)?"":str1.toString()).equals(isEmpty(str2)?"":str2.toString());

    }

    public  static Long objToLong(Object obj){
        return isEmpty(obj)?0l:Long.parseLong(obj.toString());
    }

    public static String basicToString(Object obj){

        BigDecimal bd = new BigDecimal(StringUtil.isEmpty(obj)?"0":obj.toString());

        bd = bd.divide(new BigDecimal(100),2, RoundingMode.HALF_UP);

        return bd.toString();
    }

	public static String getNowTimeStamp() {
		long time = System.currentTimeMillis();
		String nowTimeStamp = String.valueOf(time / 1000);
		return nowTimeStamp;
	}


	public static String getIpAddress(){
		ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = sra.getRequest();

		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

}
